package logica;

import java.io.Serializable;

public class ArbolDeAtributos implements Serializable {

	private static final long serialVersionUID = 1165155393028194410L;

	private Rama m_raiz;
	private Rama m_actual;

	/** Construye el arbol raiz vacia pero no null. **/
	public ArbolDeAtributos() {
		m_raiz = new Rama();
		m_actual = m_raiz;
	}

	/** Construye el arbol a partir de otro dado. **/
	public ArbolDeAtributos(ArbolDeAtributos datos) {
		if (datos != null && !datos.isEmpty())
			m_raiz = datos.m_raiz;
		else
			m_raiz = new Rama();
		m_actual = m_raiz;
	}

	/** Se situa en su rama positiva. **/
	public boolean treparRamaPositiva() {
		if (!isEmpty() && m_actual.getPositiva() != null) {
			m_actual = m_actual.getPositiva();
			return true;
		}
		return false;
	}
	
	/** Se situa en su rama negativa. **/
	public boolean treparRamaNegativa() {
		if (!isEmpty() && m_actual.getNegativa() != null) {
			m_actual = m_actual.getNegativa();
			return true;
		}
		return false;
	}

	public void volverARamaAnterior() {
		if (!isEmpty() && m_actual != m_raiz)
			m_actual = m_actual.getAnterior();
	}

	public void volverALaRaiz() {
		if (!isEmpty())
			m_actual = m_raiz;
	}

	/** Indica si aun no se empezo a recorrer el arbol. **/
	public boolean estaEnLaRaiz() {
		return m_actual == m_raiz;
	}

	public boolean ultimaRama() {
		return (!isEmpty() && m_actual.esUltima());
	}

	/** Agrega elementos nuevos partiendo de una rama dada. **/
	private boolean agregarElemento(Rama ramaActual, Elemento nuevo) {

		if (nuevo.isEmpty() || nuevo.soloAtributos()) {
			return false;
		} else if (ramaActual.isEmpty()) {
			ramaActual.setElemento(nuevo);
			return true;
		}

		/** Elimina los atributos encontrados en 'nuevo' hasta el final. **/
		while (!ramaActual.esUltima()) {
			if (nuevo.contieneAtributo(ramaActual.getElemento().getAtributo())) {
				nuevo.removerAtributo(ramaActual.getElemento().getAtributo());
				ramaActual = ramaActual.getPositiva();
			} else
				ramaActual = ramaActual.getNegativa();
		}

		/**
		 * Crea una rama de division colgando a sus lados el viejo y nuevo
		 * elemento.
		 **/
		
		Elemento actual = ramaActual.getElemento();
		Elemento divisor = actual.atributoDiferente(nuevo);

		if (divisor != null && !divisor.isEmpty()) {
			ramaActual.addNegativa(new Rama(nuevo));
			ramaActual.addPositiva(new Rama(actual));
			ramaActual.setElemento(divisor);
			return true;
		} else {
			divisor = nuevo.atributoDiferente(actual);
			if (divisor != null && !divisor.isEmpty()) {
				ramaActual.addNegativa(new Rama(actual));
				ramaActual.addPositiva(new Rama(nuevo));
				return true;
			}
		}

		return false;
	}

	/** Agrega un elemento nuevo en la posicion actual. **/
	public boolean agregarEnActual(Elemento nuevo) {
		return agregarElemento(m_actual, nuevo);
	}

	/**
	 * Agrega un elemanto nuevo partiendon desde la raiz hasta su posicion
	 * adecuada.
	 **/
	public boolean agregar(Elemento nuevo) {
		return agregarElemento(m_raiz, nuevo);
	}

	public Elemento getElemento() {
		return m_actual.getElemento();
	}

	public boolean isEmpty() {
		return m_raiz == null || m_raiz.isEmpty();
	}

	public String toString() {
		return "[ar:" + ((!isEmpty()) ? m_raiz.toString() : "") + "]";
	}
}
